package com.rtsffm.rtd.test;

import java.lang.reflect.Method;

//~--- classes ----------------------------------------------------------------

public abstract class Bench {
    final String name;

    //~--- constructors -------------------------------------------------------

    public Bench(String name) {
        this.name = name;
    }

    //~--- methods ------------------------------------------------------------

    abstract int run(int iterations) throws Throwable;

    private double time() {
        try {
            int  nextI    = 0;
            long duration = 0;

            do {
                long start = System.nanoTime();


                run(1);

                duration += (System.nanoTime() - start);
                nextI++;
            } while (nextI < 1);

            return duration * 1.0d / nextI;
        } catch (Throwable e) {
            e.printStackTrace();

            return 0d;
        }
    }

    @Override
    public String toString() {
        return name + "\t" + time() + " ns";
    }

    public static void main(String[] args) throws Exception {
        final C      invocationTarget = new C();
        final Method m                = C.class.getMethod("foo");
        final Method am               = C.class.getMethod("foo");

        am.setAccessible(true);

        Bench[] marks = { new Bench("reflective invocation (without setAccessible)") {
            @Override
            int run(int iterations) throws Throwable {
                int x = 0;

                for (int i = 0; i < iterations; i++) {
                    x += (Integer) m.invoke(invocationTarget);
                }

                return x;
            }
        }, new Bench("reflective invocation (with setAccessible)") {
            @Override
            int run(int iterations) throws Throwable {
                int x = 0;

                for (int i = 0; i < iterations; i++) {
                    x += (Integer) am.invoke(invocationTarget);
                }

                return x;
            }
        }, new Bench("direct invocation") {
            @Override
            int run(int iterations) throws Throwable {
                int x = 0;

                for (int i = 0; i < iterations; i++) {
                    x += invocationTarget.foo();
                }

                return x;
            }
        }, };

        for (Bench bm : marks) {
            System.out.println(bm);
        }
    }

    //~--- inner classes ------------------------------------------------------

    static class C {
        public Integer foo() {
            return 1;
        }
    }
}
